import datetime
import logging

import httpx
import requests
from retrying import retry

from modules.storage.file_store import FileStore
from utils.os_main import get_abs_file_path

logging.basicConfig(filename=get_abs_file_path('logs/request.log'),
                    level=logging.DEBUG,
                    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)


class RequestMain:
    """
    请求处理类，支持requests和httpx两种请求方式
    """
    
    def _setup_proxy(self, proxy):
        """
        设置代理配置
        
        Args:
            proxy (str): 代理地址，例如 '10.10.10.10:1080'
            
        Returns:
            dict: 代理配置字典
        """
        if not proxy:
            return None
            
        return {
            'http://': 'http://' + proxy,
            'https://': 'https://' + proxy,
        }
    
    def _handle_exception(self, method, url, params, proxies, e):
        """
        处理请求异常
        
        Args:
            method (str): 请求方法
            url (str): 请求地址
            params (dict): 请求参数
            proxies (dict): 代理设置
            e (Exception): 异常对象
            
        Raises:
            Exception: 重新抛出异常以触发retry机制
        """
        # 打印异常
        print(f"请求失败：{e}")
        logger.error("Error occurred: %s", str(e), exc_info=True)
        self._record_failure_info(method, url, params, proxies, e)
        # 重新抛出异常，触发 retry 机制
        raise e

    def _record_failure_info(self, method, url, params, proxies, error_message):
        """
        记录请求失败信息到文件。

        Args:
            method (str): 请求方法。
            url (str): 请求地址。
            params (dict): 请求参数。
            proxies (dict): 代理设置。
            error_message (str): 错误信息。
        """
        fail_info = {
            'method': method,
            'url': url,
            'params': params,
            'proxies': proxies,
            'error': f"请求失败：{error_message}",
            'time': datetime.datetime.now(),
            'divide': f'{"-" * 50}\n',
        }
        fail_file = FileStore(get_abs_file_path('logs/failures.log'), 'a')
        fail_file.write(fail_info)

    @retry(stop_max_attempt_number=5, retry_on_result=lambda re_data: re_data is None, wait_fixed=2000)
    def requests_request(self, method, url, params=None, data=None, json=None, headers=None, files=None, verify=False,
                         cert=None, timeout=None, proxies=None, proxy=None, **kwargs):
        """
        使用requests库发送请求
        
        Args:
            method (str): 请求方式 get/post/put/delete/patch
            url (str): 请求地址
            params (dict): 字典或bytes，作为参数增加到url中
            data (dict): data类型传参，字典、字节序列或文件对象
            json (dict): json传参
            headers (dict): 请求头
            files (dict): 上传文件 例如：{'file': open('favicon.ico', 'rb')}
            verify (bool): 是否验证SSL证书
            cert (tuple): 指定本地证书 例如：('/path/server.crt','/path/server.key')
            timeout (int/tuple): 超时设置
            proxies (dict): 代理设置
            proxy (str): 代理地址
            **kwargs: 其他参数
            
        Returns:
            Response: 请求响应对象
        """
        try:
            # 处理代理
            proxies = self._setup_proxy(proxy) or proxies
            
            # 发送请求
            return requests.session().request(
                method, url, params=params, data=data, json=json, headers=headers,
                files=files, cert=cert, timeout=timeout, verify=verify,
                proxies=proxies, **kwargs
            )
        except Exception as e:
            self._handle_exception(method, url, params, proxies, e)
            return None

    @retry(stop_max_attempt_number=5, retry_on_result=lambda re_data: re_data is None, wait_fixed=2000)
    def httpx_request(self, method, url, is_http2=False, content=None, data=None, files=None, json=None, params=None,
                      headers=None, cookies=None, timeout=None, extensions=None, proxy=None, **kwargs):
        """
        使用httpx库发送请求
        
        Args:
            method (str): 请求方式 GET/POST/PUT/DELETE/PATCH
            url (str): 请求地址
            is_http2 (bool): 是否使用HTTP/2.0
            content (bytes): 请求内容
            data (dict): 表单数据
            files (dict): 上传文件
            json (dict): JSON数据
            params (dict): URL参数
            headers (dict): 请求头
            cookies (dict): Cookie
            timeout (int/tuple): 超时设置
            extensions (dict): HTTP扩展
            proxy (str): 代理地址
            **kwargs: 其他参数
            
        Returns:
            Response: 请求响应对象
        """
        try:
            # 处理代理
            proxies = self._setup_proxy(proxy)
            
            # 发送请求
            return httpx.Client(http2=is_http2, proxies=proxies).request(
                method.upper(), url, content=content, data=data, files=files, json=json,
                params=params, headers=headers, cookies=cookies, timeout=timeout,
                extensions=extensions, **kwargs
            )
        except Exception as e:
            self._handle_exception(method, url, params, proxies, e)
            return None

    @retry(stop_max_attempt_number=5, retry_on_result=lambda re_data: re_data is None, wait_fixed=2000)
    def request(self, method, url, is_http2=False, params=None, data=None, json=None, headers=None, files=None,
                verify=False, cert=None, timeout=None, proxies=None, content=None, cookies=None, extensions=None,
                proxy=None, **kwargs):
        """
        统一请求方法，根据is_http2参数选择使用requests或httpx发送请求
        
        Args:
            method (str): 请求方式
            url (str): 请求地址
            is_http2 (bool): 是否使用HTTP/2.0
            params (dict): URL参数
            data (dict): 表单数据
            json (dict): JSON数据
            headers (dict): 请求头
            files (dict): 上传文件
            verify (bool): 是否验证SSL证书
            cert (tuple): 指定本地证书
            timeout (int/tuple): 超时设置
            proxies (dict): 代理设置
            content (bytes): 请求内容
            cookies (dict): Cookie
            extensions (dict): HTTP扩展
            proxy (str): 代理地址
            **kwargs: 其他参数
            
        Returns:
            Response: 请求响应对象
        """
        try:
            if is_http2:
                return self.httpx_request(
                    method=method, url=url, is_http2=is_http2, content=content,
                    data=data, files=files, json=json, params=params, headers=headers,
                    cookies=cookies, timeout=timeout, extensions=extensions, proxy=proxy, **kwargs
                )
            else:
                return self.requests_request(
                    method=method, url=url, params=params, data=data, json=json,
                    headers=headers, files=files, cert=cert, timeout=timeout, verify=verify,
                    proxies=proxies, proxy=proxy, **kwargs
                )
        except Exception as e:
            self._handle_exception(method, url, params, proxies, e)
            return None


# 生成Request实例
request_main = RequestMain()

if __name__ == '__main__':
    # request_requests 使用requests请求
    request_data = request_main.requests_request("get", 'https://www.baidu.com')
    if request_data:
        print(request_data.text)
        # print(request_data.code)

    # httpx 请求HTTP/2.0示例
    # response = request_main.httpx_request('GET', 'https://spa16.scrape.center/', True)
    
    # httpx 一般请求示例
    # headers = {'User-Agent': 'my-app/0.0.1'}
    # response = request_main.httpx_request('get', 'https://www.httpbin.org/get', params={'name': 'germey'})
    # print(response.text)
    
    print(datetime.datetime.now())
